home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 1 / CU Amiga Magazine CD-ROM Special Edition (1995)(EMAP Images)(GB)[Issue 1995-11].iso / Aminet / disk / moni / Val_2_3.lha / Val.c < prev    next >
C/C++ Source or Header  |  1995-04-27  |  42KB  |  1,886 lines

  1. /*
  2.  *    Copyright (C) 1988 Andrew Kemmis
  3.  *
  4.  *    All Rights Reserved
  5.  *
  6.  *    Date:    Jan 1988
  7.  */
  8. #include <ak/stdak.h>
  9. #include <ak/debug.h>
  10.  
  11. char    Program_name[]    = "Val";
  12. int    Version     = 2;
  13. int    MinorVer    = 3;
  14. char    Date[]        = "Dec 1993";
  15. char    CRDate[]    = "1988-93";
  16.  
  17. #include <ak/err.h>
  18. #include <ak/pool.h>
  19. #include <ak/dev.h>
  20. #include <ak/dos.h>
  21. #include <intuition/intuitionbase.h>
  22. #include "val.h"
  23.  
  24. #include "val.qi"
  25.  
  26. #define ULONGS(l)       ((ulong)(l)*(ulong)sizeof(ulong))
  27. #define ZAlloc(a)       PoolAlloc((a), sizeof(*(a)), &GenPoolKey)
  28. #define LAlloc(a,n,z)   {       if (!Seek)\
  29.                     PoolAlloc((a), ULONGS(n), &GenPoolKey);\
  30.                 else\
  31.                     (char *)(a) = AllocMem(ULONGS(n), 0L);\
  32.             }
  33.  
  34. #define ULONGMAX    4294967295
  35.  
  36. extern    char    *strchr();
  37. extern    char    *strrchr();
  38. extern    int    strlen();
  39. extern    int    strcmp();
  40. extern    int    sscanf();
  41.  
  42. int    cli;
  43.  
  44. struct    IBASE    *IBASE = (struct IBASE *)NULL;
  45.  
  46. Static    int    FileSystem;
  47.  
  48. #define IS_OFS    0
  49. #define IS_FFS    1
  50.  
  51. Static    char    StrRoot[] = "Root";
  52. Static    char    StrBitMap[] = "BitMap";
  53. Static    char    StrEtc[] = "Dir,Fil,Lnk";
  54. Static    char    StrDir[] = "Dir";
  55. Static    char    StrFil[] = "Fil";
  56. Static    char    StrExt[] = "Ext";
  57. Static    char    StrDat[] = "Dat";
  58. Static    char    StrSoftLnk[] = "SoftLnk";
  59. Static    char    StrDirLnk[] = "DirLnk";
  60. Static    char    StrFilLnk[] = "FilLnk";
  61. Static    char    StrNextD[] = "NextDat";
  62. Static    char    StrChain[] = "HashChain";
  63. Static    char    StrNext[] = "Next";
  64. Static    char    StrPrev[] = "Prev";
  65. Static    char    StrHuh[] = "Unknown";
  66. Static    struct    AkDevStuff    Stuff = DEVSTUFFINIT;
  67. Static    uchar    *Buffer;
  68. Static    long    Dev = -1;
  69. Static    struct    Names    RootName =
  70.     {    (struct Names *)NULL,   (struct Names *)NULL,   ULONGMAX, };
  71. Static    struct    Links
  72. {    ushort    type;
  73.     ulong    block;
  74.     ulong    prev;
  75.     ulong    next;
  76.     struct    Links    *another;
  77. } *LinkHead, *LinkMaybe;
  78. Static    uchar    *FName;
  79. Static    int    Inhibited = 0;
  80.  
  81. Static    struct    PoolKey BufPoolKey;
  82. Static    struct    PoolKey GenPoolKey;
  83. Static    struct    PoolKey ZerPoolKey;
  84.  
  85. Static    ulong    ReadCount = 0;
  86. Static    struct    Info    *LastInfo;
  87. Static    ulong    LastBlk;
  88. Static    uchar    *MyBitMap;
  89.  
  90. Static    ulong    ReadSmall = 0;
  91. Static    ulong    ReadLarge = 0;
  92. Static    ulong    ReadLNum = 0;
  93. Static    ulong    HitSmall = 0;
  94. Static    ulong    HitLarge = 0;
  95. Static    ulong    MicSta;
  96. Static    ulong    MicFin;
  97. Static    ulong    MicCode;
  98. Static    ulong    MicRead;
  99.  
  100. #define BMAP_TST(n)      (MyBitMap[(n)>>3]&(1<<((n)&7)))
  101. #define BMAP_SET(n)      (MyBitMap[(n)>>3]|=(1<<((n)&7)))
  102.  
  103. Static Copy(d, s, l, siz)
  104. REG    char    *d;
  105. REG    char    *s;
  106. REG    ulong    l;
  107. REG    int    siz;
  108. {
  109.     REG    ulong  len = l * (ulong)siz;
  110.  
  111. DBGS(">C");
  112.  
  113.     while (len--)
  114.         *(d++) = *(s++);
  115.  
  116. DBGS("<C");
  117. }
  118.  
  119. Static Get(Rem, num)
  120. REG    struct    Info    *Rem;
  121. REG    ulong    num;
  122. {
  123. DBGS(">G");
  124.  
  125.     if ((Rem - InfoList) >= MaxDepth)
  126.         MyError(ERR_TOODEEP, MaxDepth);
  127.  
  128.     getblok(num + Stuff.Info.Begin, Rem);
  129.  
  130. DBGS("<G");
  131. }
  132.  
  133. Static LONG DevRead(num, buf, size)
  134. REG    ulong    num;
  135. REG    ulong    *buf;
  136. REG    LONG    size;
  137. {
  138.     REG    LONG    ret;
  139.     REG    int    retry = Retries + 1;
  140.  
  141. DBGS(">DR");
  142.  
  143.     while (retry-- && (ret = AkDevRead(num, buf, &Stuff, size)))
  144.         ;
  145.  
  146.     if (ret && FailReq)
  147.     {    if (!akrequester("Disk Read Error", "Continue", "Abort"))
  148.         {    puts("Aborted at users request on Read Error");
  149.             Cleanup();
  150.         }
  151.     }
  152.  
  153. DBGS("<DR");
  154.  
  155.     return(ret);
  156. }
  157.  
  158. Static    int    DoCache = !0;
  159.  
  160. #define CACHE_INVALID    -7
  161.  
  162. Static LONG CacheRead(num, buf)
  163. REG    ulong    num;
  164. REG    ulong    **buf;
  165. {
  166.     static    ulong    cache0 = CACHE_INVALID;
  167.     static    ulong    cache1 = CACHE_INVALID;
  168.     static    ulong    cache2 = CACHE_INVALID;
  169.     REG    LONG    ret = 0;
  170.  
  171. DBGS(">CR");
  172.  
  173.     *buf = (ulong *)Buffer;
  174.  
  175.     if (Cache == 1)
  176.         ret = DevRead(num, *buf, BLOCK_SIZE);
  177.     else
  178.     {    if (num == cache0 || num == (cache0 + 1) || (cache1 <= num && num <= cache2))
  179.         {    if (StatCache)
  180.                 MicSta = IBASE->Micros;
  181.  
  182.             if (num == (cache0+1))
  183.                 *buf = (ulong *)&Buffer[BLOCK_SIZE];
  184.             else
  185.             if (num != cache0)
  186.                 *buf = (ulong *)&Buffer[BLOCK_SIZE*(2 + num - cache1)];
  187.  
  188.             if (StatCache)
  189.                 MicFin = IBASE->Micros;
  190.  
  191.             if (StatCache)
  192.             {    if (num == cache0 || num == (cache0+1))
  193.                     HitSmall++;
  194.                 else
  195.                     HitLarge++;
  196.  
  197.                 if (MicSta > MicFin)
  198.                     MicFin += 1000000;
  199.                 MicCode += (MicFin - MicSta);
  200.             }
  201.             if (DebugCache)
  202.             {    if (num == cache0)
  203.                     printf("Hit at :0\n");
  204.                 else
  205.                 if (num == (cache0+1))
  206.                     printf("Hit at :1\n");
  207.                 else
  208.                     printf("Hit at %lu\n", 2 + num - cache1);
  209.             }
  210.         }
  211.         else
  212.         {    if (DebugCache)
  213.             {    if (DoCache && num <= (Stuff.Info.End - 2))
  214.                     printf("Do  Cache (miss %ld %ld)\n", num-cache0, num-cache1);
  215.                 else
  216.                     printf("Non Cache (miss %ld %ld)\n", num-cache0, num-cache1);
  217.             }
  218.  
  219.             if (StatCache)
  220.                 MicSta = IBASE->Micros;
  221.  
  222.             if (DoCache && num <= (Stuff.Info.End - 2))     /* Must read 3 Blocks! */
  223.             {    cache0 = num;
  224.                 cache1 = num + 2;
  225.                 cache2 = num + Cache - 1;
  226.                 if (cache2 > Stuff.Info.End)
  227.                     cache2 = Stuff.Info.End;
  228.                 ret = DevRead(num, *buf, BLOCK_SIZE*(1 + cache2 - cache0));
  229.                 if (ret)
  230.                     cache0 = cache1 = cache2 = CACHE_INVALID;
  231.             }
  232.             else
  233.             {    if (num != Stuff.Info.End)
  234.                     cache0 = num;
  235.                 else
  236.                 {    cache0 = num - 1;
  237.                     *buf = (ulong *)&Buffer[BLOCK_SIZE];
  238.                 }
  239.  
  240.                 ret = DevRead(num, (ulong *)Buffer, BLOCK_SIZE*2);
  241.                 if (ret)
  242.                     cache0 = CACHE_INVALID;
  243.             }
  244.  
  245.             if (StatCache)
  246.                 MicFin = IBASE->Micros;
  247.  
  248.             if (StatCache)
  249.             {    if (DoCache && num <= (Stuff.Info.End - 2))
  250.                 {    ReadLarge++;
  251.                     ReadLNum += (1 + cache2 - cache0);
  252.                 }
  253.                 else
  254.                     ReadSmall++;
  255.  
  256.                 if (MicSta > MicFin)
  257.                     MicFin += 1000000;
  258.                 MicRead += (MicFin - MicSta);
  259.             }
  260.         }
  261.     }
  262. DBGS("<CR");
  263.     return(ret);
  264. }
  265.  
  266. Static char *StrType(type)
  267. REG    ushort    type;
  268. {
  269.     REG    char    *ans;
  270.  
  271.     switch(type)
  272.     {
  273.     case I_ROOT:
  274.         ans = StrRoot;
  275.         break;
  276.     case I_DIR:
  277.         ans = StrDir;
  278.         break;
  279.     case I_FIL:
  280.         ans = StrFil;
  281.         break;
  282.     case I_EXT:
  283.         ans = StrExt;
  284.         break;
  285.     case I_DAT:
  286.         ans = StrDat;
  287.         break;
  288.     case I_S_LNK:
  289.         ans = StrSoftLnk;
  290.         break;
  291.     case I_H_LNK_DIR:
  292.         ans = StrDirLnk;
  293.         break;
  294.     case I_H_LNK_FIL:
  295.         ans = StrFilLnk;
  296.         break;
  297. /*
  298.     case I_UNK:
  299.     case I_UNREADABLE:
  300. */
  301.     default:
  302.         ans = StrHuh;
  303.         break;
  304.     }
  305.     return(ans);
  306. }
  307.  
  308. Static    int    BaD = 0;
  309. Static    int    WaR = 0;
  310. Static    ulong    SeqNum;
  311. Static    ulong    PrevD = 0;
  312. Static    ulong    NextD = 0;
  313.  
  314. #define B_TYP        0
  315. #define B_KEY        1
  316. #define B_CHKSUM    2
  317. #define B_BMAP        3
  318. #define B_PAR        4
  319. #define B_COUNT     5
  320. #define B_FIRST     6
  321. #define B_BYTESIZE    7
  322. #define B_HED        8
  323. #define B_RANGE     9
  324. #define B_SEQ        10
  325. #define B_SHORT     11
  326. #define B_BMFLG     12
  327. #define B_HTSIZ     13
  328. #define B_BITMAP    14
  329. #define B_NEXTD     15
  330. #define B_BADNAME    16
  331. #define B_UNR        17
  332. #define B_BLOCKSIZE    18
  333. #define B_USED        19
  334. #define B_USEDBY    20
  335.  
  336. #define B_PREVLINK    22
  337. #define B_NEXTLINK    23
  338. #define B_OFSLINK    24
  339. #define B_NOPREVLINK    25
  340. #define B_PREVINV    26
  341. #define B_NOTPREV    27
  342. #define B_PREVDIF    28
  343. #define B_LINKTYPERR    29
  344. #define B_XNOTLINK    30
  345.  
  346. Static bad(Rem, num, err, typ, ex1, ex2, ex3)
  347. struct    Info    *Rem;
  348. REG    ulong    num;
  349. int    err;
  350. REG    char    *typ;
  351. REG    ulong    ex1;
  352. ulong    ex2;
  353. ulong    ex3;
  354. {
  355.     int    idx;
  356.     ulong    blk;
  357.     REG    struct    Info    *CurRem;
  358.     REG    struct    Names    *CurName;
  359.     ulong    *Buf = (ulong *)Buffer;
  360.     int    seeked = 0;
  361.  
  362. DBGS(">b");
  363.  
  364.     switch(err)
  365.     {
  366.     case B_BMFLG:
  367.     case B_BITMAP:
  368.     case B_HTSIZ:
  369.     case B_BMAP:
  370.     case B_BLOCKSIZE:
  371.     case B_BYTESIZE:
  372.     case B_OFSLINK:
  373.         WaR++;
  374.         printf("War: B %lu %s ", num, typ);
  375.         break;
  376.     default:
  377.         BaD++;
  378.         printf("Err: B %lu %s ", num, typ);
  379.         break;
  380.     }
  381.  
  382.     if (Rem && DosNames && num != Stuff.Info.Root)
  383.     {    CurRem = LastInfo;
  384.         if (Seek)
  385.             idx = CurRem - InfoList;
  386.         else
  387.             for (idx=0; CurRem != &InfoList[Stuff.Info.Root]; idx++)
  388.                 CurRem = &InfoList[CurRem->Obj.dir->parent];
  389.                     /* *** parent in same pos */
  390.  
  391.         CurName = &RootName;
  392.         while (idx--)
  393.         {    if (CurName->next == (struct Names *)NULL)
  394.             {
  395. DEBUGMEM_NAME("A CurName");
  396.                 ZAlloc(CurName->next);
  397.                 CurName->next->prev = CurName;
  398.                 CurName->next->next = (struct Names *)NULL;
  399.                 CurName->next->block = ULONGMAX;
  400.             }
  401.             CurName = CurName->next;
  402.         }
  403.         if (CurName->next)
  404.             CurName->next->block = ULONGMAX;
  405.  
  406.         CurRem = LastInfo;
  407.         blk = LastBlk;
  408.         while (CurName)
  409.         {    if (CurName->block != blk)
  410.             {    CurName->block = blk;
  411.                 if (!Seek && !seeked)
  412.                 {    AkMotorOn(&Stuff);
  413.                     seeked = !0;
  414.                 }
  415.                 if (CacheRead(blk + Stuff.Info.Begin, &Buf))
  416.                     FName = (uchar *)"\011***Bad***";
  417.                 else
  418.                     FName = (uchar *)(&Buf[POS_NAME]);
  419.                 if (*FName >= sizeof(RootName.name))
  420.                     *FName = sizeof(RootName.name) - 1;
  421.                 Copy(CurName->name, FName, (long)((*FName) + 1), sizeof(char));
  422.             }
  423.             if (Seek)
  424.                 blk = (CurRem--)->Obj.dir->parent;
  425.                     /* *** parent in same pos, blk not used if Root */
  426.             else
  427.                 blk = InfoList[blk].Obj.dir->parent;
  428.                     /* *** parent in same pos, blk not used if Root  */
  429.  
  430.             CurName = CurName->prev;
  431.         }
  432.         if (seeked)
  433.             AkMotorOff(&Stuff);
  434.  
  435.         CurName = &RootName;
  436.         while (CurName && CurName->block != ULONGMAX)
  437.         {    if (CurName->prev)
  438.             {    if (CurName->prev == &RootName)
  439.                     putchar(':');
  440.                 else
  441.                     putchar('/');
  442.             }
  443.             if (*CurName->name)
  444.                 printf("%.*s", (int)(*(CurName->name)), (CurName->name)+1);
  445.             CurName = CurName->next;
  446.         }
  447.         putchar(' ');
  448.     }
  449.  
  450.     switch(err)
  451.     {
  452.     case B_TYP:
  453.         printf("Block type wrong (par = %lu)", ex1);
  454.         break;
  455.     case B_KEY:
  456.         printf("Key wrong (par = %lu)", ex1);
  457.         break;
  458.     case B_CHKSUM:
  459.         printf("Checksum wrong (par = %lu)", ex1);
  460.         break;
  461.     case B_BMAP:
  462.         printf("No Bitmap blocks present!");
  463.         break;
  464.     case B_PAR:
  465.         printf("Parent pointer (%lu) != parent block (%lu)", ex1, ex2);
  466.         break;
  467.     case B_COUNT:
  468.         printf("Block Count incorrect (par = %lu)", ex1);
  469.         break;
  470.     case B_FIRST:
  471.         printf("FirstData incorrect (should be = %lu)", ex1);
  472.         break;
  473.     case B_BYTESIZE:
  474.         printf("Bytesize incorrect (calc = %lu actual = %lu)", ex1, ex2);
  475.         break;
  476.     case B_HED:
  477.         printf("Header pointer (%lu) != header block (%lu)", ex1, ex2);
  478.         break;
  479.     case B_RANGE:
  480.         printf("%s pointer (%lu) out of disk range!", ex1, ex2);
  481.         break;
  482.     case B_SEQ:
  483.         printf("Sequence number wrong (should be %lu, is %lu)", ex1, ex2);
  484.         break;
  485.     case B_SHORT:
  486.         printf("Data block not full (only allowed in last data block!)");
  487.         break;
  488.     case B_BMFLG:
  489.         printf("Bitmap Flag says Bitmap is invalid!");
  490.         break;
  491.     case B_HTSIZ:
  492.         printf("Hash table size != calculated size!");
  493.         break;
  494.     case B_BITMAP:
  495.         printf("Block type NOT unknown type!");
  496.         break;
  497.     case B_NEXTD:
  498.         printf("Next data block (%lu) != Previous data block's (%lu) Next data block (%lu)",
  499.             ex1, ex2, ex3);
  500.         break;
  501.     case B_BADNAME:
  502.         printf("Blocks name is invalid (BSTR size is 0 or > %d)", sizeof(RootName.name) - 1);
  503.         break;
  504.     case B_UNR:
  505.         printf("Gave error (0x%lx) on read (par = %lu)", ex1, ex2);
  506.         break;
  507.     case B_BLOCKSIZE:
  508.         printf("Total blocks incorrect (calc = %lu actual = %lu)", ex1, ex2);
  509.         break;
  510.     case B_USED:
  511.         if (ex1)
  512.             printf("Pointed to by %lu ", ex1);
  513.         printf("Already used (FFS Error)");
  514.         break;
  515.     case B_USEDBY:
  516.         printf("Pointed to by %lu Already used by %lu (FFS Error)", ex1, ex2);
  517.         break;
  518.     case B_PREVLINK:
  519.         printf("Prev Link Pointer not 0");
  520.         break;
  521.     case B_NEXTLINK:
  522.         printf("Next Link Pointer not 0");
  523.         break;
  524.     case B_OFSLINK:
  525.         printf("Contains a link (but partition is OFS)");
  526.         break;
  527.     case B_NOPREVLINK:
  528.         printf("Prev Link Pointer should not be 0");
  529.         break;
  530.     case B_PREVINV:
  531.         printf("Prev (%lu) Must be Fil or Dir (not %s)", ex1, ex2);
  532.         break;
  533.     case B_NOTPREV:
  534.         printf("Next's (%lu) Prev (%lu) should be This", ex1, ex2);
  535.         break;
  536.     case B_PREVDIF:
  537.         printf("Next's (%lu) Prev (%lu) != This Prev (%lu)", ex3, ex2, ex1);
  538.         break;
  539.     case B_LINKTYPERR:
  540.         printf("%s Pointer's type (%s) not valid for this type", ex1, ex2);
  541.         break;
  542.     case B_XNOTLINK:
  543.         printf("%s (%lu) is not Linked", ex1, ex2);
  544.         break;
  545.     }
  546.     putchar('\n');
  547.  
  548.     if (ErrLimit >= 0 && BaD > ErrLimit)
  549.     {    printf("Validation aborted ... Error Limit (%ld) Exceeded\n", ErrLimit);
  550.         Cleanup();
  551.     }
  552.  
  553.     if (WarnLimit >= 0 && WaR > WarnLimit)
  554.     {    printf("Validation aborted ... Warning Limit (%ld) Exceeded\n", WarnLimit);
  555.         Cleanup();
  556.     }
  557.  
  558. DBGS("<b");
  559. }
  560.  
  561. Static CompareLinkType(prev_is_head, prev, next)
  562. REG    int    prev_is_head;
  563. REG    ushort    prev;
  564. REG    ushort    next;
  565. {
  566.     int    ret = FALSE;
  567.  
  568.     if (!prev_is_head)
  569.     {    if (prev == I_H_LNK_DIR && next == I_H_LNK_DIR)
  570.             ret = TRUE;
  571.  
  572.         if (prev == I_H_LNK_FIL && next == I_H_LNK_FIL)
  573.             ret = TRUE;
  574.     }
  575.     else
  576.     {    if (prev == I_DIR && next == I_H_LNK_DIR)
  577.             ret = TRUE;
  578.  
  579.         if (prev == I_FIL && next == I_H_LNK_FIL)
  580.             ret = TRUE;
  581.     }
  582.  
  583.     return(ret);
  584. }
  585.  
  586. /* OK this is really quite slow - but I don't have many links! */
  587. Static CheckLinks()
  588. {
  589.     REG    struct    Links    *LinkTmp;
  590.     REG    struct    Links    *LinkTmp2;
  591.     REG    ulong    next;
  592.     REG    ulong    prev;
  593.     REG    ulong    block;
  594.     ushort    type;
  595.     int    got_prev;
  596.     int    got_next;
  597.  
  598.     LinkTmp = LinkHead;
  599.     while (LinkTmp)
  600.     {    next = LinkTmp->next;
  601.         prev = LinkTmp->prev;
  602.         block = LinkTmp->block;
  603.         type = LinkTmp->type;
  604.         got_prev = !prev;
  605.         got_next = !next;
  606.  
  607.         LinkTmp2 = LinkHead;
  608.         while (LinkTmp2)
  609.         {    if (prev && prev == LinkTmp2->block)
  610.             {    got_prev = !0;
  611.                 if (LinkTmp2->type != I_DIR && LinkTmp2->type != I_FIL)
  612.                     bad(NULL, block, B_PREVINV, StrType(type), prev, StrType(LinkTmp2->type));
  613.  
  614.                 if (!CompareLinkType(!0, LinkTmp2->type, type))
  615.                     bad(NULL, block, B_LINKTYPERR, StrType(type), StrPrev, StrType(LinkTmp2->type));
  616.             }
  617.             if (next && next == LinkTmp2->block)
  618.             {    got_next = !0;
  619.                 if (!prev && LinkTmp2->prev != block)
  620.                     bad(NULL, block, B_NOTPREV, StrType(type), next, LinkTmp2->prev);
  621.  
  622.                 if (prev && LinkTmp2->prev != prev)
  623.                     bad(NULL, block, B_PREVDIF, StrType(type), prev, LinkTmp2->prev, next);
  624.  
  625.                 if (!CompareLinkType(prev == 0, type, LinkTmp2->type))
  626.                     bad(NULL, block, B_LINKTYPERR, StrType(type), StrNext, StrType(LinkTmp2->type));
  627.             }
  628.             LinkTmp2 = LinkTmp2->another;
  629.         }
  630.         if (!got_prev)
  631.             bad(NULL, block, B_XNOTLINK, StrType(type), StrPrev, prev);
  632.         if (!got_next)
  633.             bad(NULL, block, B_XNOTLINK, StrType(type), StrNext, next);
  634.         LinkTmp = LinkTmp->another;
  635.     }
  636. }
  637.  
  638. Static MoveMaybe(block)
  639. REG    ulong    block;
  640. {
  641.     REG    struct    Links    *LinkTmpPrev = NULL;
  642.     REG    struct    Links    *LinkTmp = LinkMaybe;
  643.  
  644.     while (LinkTmp && LinkTmp->block != block)
  645.     {    LinkTmpPrev = LinkTmp;
  646.         LinkTmp = LinkTmp->another;
  647.     }
  648.  
  649.     if (LinkTmp)
  650.     {    if (LinkTmpPrev)
  651.             LinkTmpPrev->another = LinkTmp->another;
  652.         else
  653.             LinkMaybe = LinkTmp->another;
  654.  
  655.         LinkTmp->another = LinkHead;
  656.         LinkHead = LinkTmp;
  657.     }
  658.     else
  659.     {    /* Huh? Shouldn't happen? */
  660.         MyError(ERR_NOVAL, "Link Code Bug");
  661.     }
  662. }
  663.  
  664. Static AddLink(block, prev, next, type)
  665. REG    ulong    block;
  666. REG    ulong    prev;
  667. REG    ulong    next;
  668. REG    ushort    type;
  669. {
  670.     struct    Links    *LinkTmp;
  671.  
  672. DBGS(">AL");
  673.  
  674. DEBUGMEM_NAME("A LinkTmp");
  675.     ZAlloc(LinkTmp);
  676.     LinkTmp->type = type;
  677.     LinkTmp->block = block - Stuff.Info.Begin;
  678.     LinkTmp->prev = prev;
  679.     LinkTmp->next = next;
  680.     LinkTmp->another = LinkMaybe;
  681.     LinkMaybe = LinkTmp;
  682.  
  683. DBGS("<AL");
  684. }
  685.  
  686. Static getblok(num, Rem)
  687. ulong    num;
  688. REG    struct    Info    *Rem;
  689. {
  690.     REG    ulong  *Buf;
  691.     REG    uchar  *obj;
  692.     REG    ulong  i;
  693.     REG    ulong  *l;
  694.     REG    ulong  *l2;
  695.     ulong    count;
  696.     ushort    *flags;
  697.     LONG    ret;
  698.     ulong    *buf;
  699.  
  700. DBGS(">gb");
  701.  
  702.     if (ShowReads && (++ReadCount % Count) == 0)
  703.     {    akdeco(ReadCount, 'l', NULL, NULL, NULL, ' ', ' ');
  704.         akhexo(num, 'l', NULL, NULL, NULL, '\r', '0');
  705.     }
  706.     if (Tracks && (ReadCount++ % Stuff.Info.Cyl) == 0)
  707.         akdeco(ReadCount / Stuff.Info.Cyl, 'l', NULL, NULL, NULL, '\r', ' ');
  708.  
  709.     ret = CacheRead(num, &buf);
  710.  
  711.     if (!Seek)
  712.         Rem = &InfoList[num - Stuff.Info.Begin];
  713.  
  714.     flags = &(Rem->flags);
  715.     *flags = 0;
  716.  
  717.     if (ret)
  718.     {    Rem->type = I_UNREADABLE;
  719.         Rem->Obj.ret = ret;
  720. DBGS("<gb");
  721.         return;         /* N.B. */
  722.     }
  723.  
  724.     Buf = buf;
  725.  
  726.     switch(Buf[POS_TYP])
  727.     {
  728.     case TYP_CONTROL:
  729.         FName = (uchar *)(&Buf[POS_NAME]);
  730.         if (*FName == 0 || *FName >= sizeof(RootName.name))
  731.             *flags |= E_BADNAME;
  732.         switch(Buf[POS_SEC])
  733.         {
  734.         case SEC_ROOT:
  735.             Rem->type = I_ROOT;
  736.             if (Buf[POS_KEY])
  737.                 *flags |= E_KEY;
  738.  
  739. /* Appears to be a date at POS_LINK_NEXT
  740.             if (Buf[POS_LINK_PREV])
  741.                 *flags |= E_PREVLINK;
  742.             if (Buf[POS_LINK_NEXT])
  743.                 *flags |= E_NEXTLINK;
  744. */
  745.             if (!Buf[POS_BMFLG])
  746.                 *flags |= E_BMFLG;
  747.             if (Buf[POS_HTSIZ] != (1L + POS_LST_BLK - POS_FST_BLK))
  748.                 *flags |= E_HTSIZ;
  749.             if (Seek)
  750.                 (struct Root *)obj = Rem->Obj.root;
  751.             else
  752.             {
  753. DEBUGMEM_NAME("Root");
  754.                 ZAlloc((struct Root *)obj);
  755.                 Rem->Obj.root = (struct Root *)obj;
  756.             }
  757.             for (count = 0, i = POS_FST_BLK, l = &Buf[i]; i <= POS_LST_BLK; l++, i++)
  758.                 if (*l)
  759.                     count++;
  760.             if (count++)
  761.             {
  762. DEBUGMEM_NAME("Root Blk List");
  763.                 LAlloc(l, count, StrRoot);
  764.                 ((struct Root *)obj)->blocks = l;
  765.                 for (i = POS_FST_BLK, l2 = &Buf[i]; i <= POS_LST_BLK; l2++, i++)
  766.                     if (*l2)
  767.                         *(l++) = *l2;
  768.                 *l = 0L;
  769.             }
  770.             else
  771.                 ((struct Root *)obj)->blocks = (ulong *)NULL;
  772.  
  773.             for (i = POS_BBLK, l = &Buf[i]; *l && i < POS_BBLK_END; i++, l++)
  774.                 ;
  775.             count = i - POS_BBLK;
  776.             if (*l)
  777.                 count++;
  778.             if (count)
  779.             {
  780. DEBUGMEM_NAME("A BitMap Blk List");
  781.                 LAlloc(l, count+1, StrBitMap);
  782.                 Copy(l, &Buf[POS_BBLK], count, sizeof(ulong));
  783.                 ((struct Root *)obj)->bblocks = l;
  784.                 l[count] = 0L;
  785.             }
  786.             else
  787.                 ((struct Root *)obj)->bblocks = (ulong *)NULL;
  788.             break;
  789.         case SEC_DIR:
  790.             Rem->type = I_DIR;
  791.             if (Buf[POS_KEY] != (num - Stuff.Info.Begin))
  792.                 *flags |= E_KEY;
  793.             if (Buf[POS_LINK_PREV])
  794.                 *flags |= E_PREVLINK;
  795.             if (Buf[POS_LINK_NEXT])
  796.             {    if (FileSystem == IS_OFS && !LinksAllowed)
  797.                     *flags |= E_OFSLINK;
  798.                 AddLink(num, 0L, Buf[POS_LINK_NEXT], I_DIR);
  799.             }
  800.             if (Seek)
  801.                 (struct Dir *)obj = Rem->Obj.dir;
  802.             else
  803.             {
  804. DEBUGMEM_NAME("A Dir");
  805.                 ZAlloc((struct Dir *)obj);
  806.                 Rem->Obj.dir = (struct Dir *)obj;
  807.             }
  808.             for (count = 0, i = POS_FST_BLK, l = &Buf[i]; i <= POS_LST_BLK; l++, i++)
  809.                 if (*l)
  810.                     count++;
  811.             if (count++)
  812.             {
  813. DEBUGMEM_NAME("A Dir Blk List");
  814.                 LAlloc(l, count, StrDir);
  815.                 ((struct Dir *)obj)->blocks = l;
  816.                 for (i = POS_FST_BLK, l2 = &Buf[i]; i <= POS_LST_BLK; l2++, i++)
  817.                     if (*l2)
  818.                         *(l++) = *l2;
  819.                 *l = 0L;
  820.             }
  821.             else
  822.                 ((struct Dir *)obj)->blocks = (ulong *)NULL;
  823.  
  824.             ((struct Dir *)obj)->chain = Buf[POS_HASH_CH];
  825.             ((struct Dir *)obj)->parent = Buf[POS_PAR];
  826.             ((struct Dir *)obj)->next = Buf[POS_LINK_NEXT];
  827.             break;
  828.         case SEC_FIL:
  829.             Rem->type = I_FIL;
  830.             if (Buf[POS_KEY] != (num - Stuff.Info.Begin))
  831.                 *flags |= E_KEY;
  832.             if (Buf[POS_LINK_PREV])
  833.                 *flags |= E_PREVLINK;
  834.             if (Buf[POS_LINK_NEXT])
  835.             {    if (FileSystem == IS_OFS && !LinksAllowed)
  836.                     *flags |= E_OFSLINK;
  837.                 AddLink(num, 0L, Buf[POS_LINK_NEXT], I_FIL);
  838.             }
  839.             if (Seek)
  840.                 (struct Fil *)obj = Rem->Obj.fil;
  841.             else
  842.             {
  843. DEBUGMEM_NAME("A Fil");
  844.                 ZAlloc((struct Fil *)obj);
  845.                 Rem->Obj.fil = (struct Fil *)obj;
  846.             }
  847.             for (i=POS_LST_BLK, l = &Buf[i]; *l && i > POS_FST_BLK; i--, l--)
  848.                 ;
  849.             count = POS_LST_BLK - i;
  850.             if (*l)
  851.                 count++;
  852.             else
  853.                 l++;
  854.             if (count != Buf[POS_NUM_BLK])
  855.                 *flags |= E_COUNT;
  856.             ((struct Fil *)obj)->num = count;
  857.             if (count)
  858.             {    if (Buf[POS_FST_DAT] != Buf[POS_LST_BLK])
  859.                     *flags |= E_FIRST;
  860. DEBUGMEM_NAME("A Fil Blk List");
  861.                 LAlloc(l2, count, StrFil);
  862.                 Copy(l2, l, count, sizeof(ulong));
  863.                 ((struct Fil *)obj)->blocks = l2;
  864.             }
  865.             else
  866.             {    ((struct Fil *)obj)->blocks = (ulong *)NULL;
  867.                 if (Buf[POS_FST_DAT])
  868.                     *flags |= E_FIRST;
  869.             }
  870.             ((struct Fil *)obj)->bytesize = Buf[POS_F_BYTSIZ];
  871.             ((struct Fil *)obj)->chain = Buf[POS_HASH_CH];
  872.             ((struct Fil *)obj)->parent = Buf[POS_PAR];
  873.             ((struct Fil *)obj)->extension = Buf[POS_EXT];
  874.             ((struct Fil *)obj)->next = Buf[POS_LINK_NEXT];
  875.             break;
  876.         case SEC_S_LNK:
  877.             Rem->type = I_S_LNK;
  878.             if (Buf[POS_KEY] != (num - Stuff.Info.Begin))
  879.                 *flags |= E_KEY;
  880.             if (Buf[POS_LINK_PREV])
  881.                 *flags |= E_PREVLINK;
  882.             if (Buf[POS_LINK_NEXT])
  883.                 *flags |= E_NEXTLINK;
  884.             if (FileSystem == IS_OFS && !LinksAllowed)
  885.                 *flags |= E_OFSLINK;
  886.             if (Seek)
  887.                 (struct Lnk *)obj = Rem->Obj.lnk;
  888.             else
  889.             {
  890. DEBUGMEM_NAME("A Lnk");
  891.                 ZAlloc((struct Lnk *)obj);
  892.                 Rem->Obj.lnk = (struct Lnk *)obj;
  893.             }
  894.             ((struct Lnk *)obj)->chain = Buf[POS_HASH_CH];
  895.             ((struct Lnk *)obj)->parent = Buf[POS_PAR];
  896.             break;
  897.         case SEC_H_LNK_DIR:
  898.             Rem->type = I_H_LNK_DIR;
  899.             if (Buf[POS_KEY] != (num - Stuff.Info.Begin))
  900.                 *flags |= E_KEY;
  901.             if (!Buf[POS_LINK_PREV])
  902.                 *flags |= E_PREVLINK;
  903.             if (FileSystem == IS_OFS && !LinksAllowed)
  904.                 *flags |= E_OFSLINK;
  905.             AddLink(num, Buf[POS_LINK_PREV], Buf[POS_LINK_NEXT], I_H_LNK_DIR);
  906.             if (Seek)
  907.                 (struct DirLnk *)obj = Rem->Obj.dirlnk;
  908.             else
  909.             {
  910. DEBUGMEM_NAME("A DirLnk");
  911.                 ZAlloc((struct DirLnk *)obj);
  912.                 Rem->Obj.dirlnk = (struct DirLnk *)obj;
  913.             }
  914.             ((struct DirLnk *)obj)->prev = Buf[POS_LINK_PREV];
  915.             ((struct DirLnk *)obj)->next = Buf[POS_LINK_NEXT];
  916.             ((struct DirLnk *)obj)->chain = Buf[POS_HASH_CH];
  917.             ((struct DirLnk *)obj)->parent = Buf[POS_PAR];
  918.             break;
  919.         case SEC_H_LNK_FIL:
  920.             Rem->type = I_H_LNK_FIL;
  921.             if (Buf[POS_KEY] != (num - Stuff.Info.Begin))
  922.                 *flags |= E_KEY;
  923.             if (!Buf[POS_LINK_PREV])
  924.                 *flags |= E_PREVLINK;
  925.             if (FileSystem == IS_OFS && !LinksAllowed)
  926.                 *flags |= E_OFSLINK;
  927.             AddLink(num, Buf[POS_LINK_PREV], Buf[POS_LINK_NEXT], I_H_LNK_FIL);
  928.             if (Seek)
  929.                 (struct FilLnk *)obj = Rem->Obj.fillnk;
  930.             else
  931.             {
  932. DEBUGMEM_NAME("A FilLnk");
  933.                 ZAlloc((struct FilLnk *)obj);
  934.                 Rem->Obj.fillnk = (struct FilLnk *)obj;
  935.             }
  936.             ((struct FilLnk *)obj)->prev = Buf[POS_LINK_PREV];
  937.             ((struct FilLnk *)obj)->next = Buf[POS_LINK_NEXT];
  938.             ((struct FilLnk *)obj)->chain = Buf[POS_HASH_CH];
  939.             ((struct FilLnk *)obj)->parent = Buf[POS_PAR];
  940.             break;
  941.         default:
  942.             Rem->type = I_UNK;
  943.             break;
  944.         }
  945.         break;
  946.     case TYP_EXT:
  947.         Rem->type = I_EXT;
  948.         if (Buf[POS_KEY] != (num - Stuff.Info.Begin))
  949.             *flags |= E_KEY;
  950.         if (Seek)
  951.             (struct Ext *)obj = Rem->Obj.ext;
  952.         else
  953.         {
  954. DEBUGMEM_NAME("An Ext");
  955.             ZAlloc((struct Ext *)obj);
  956.             Rem->Obj.ext = (struct Ext *)obj;
  957.         }
  958.         if (Buf[POS_FST_DAT])
  959.             *flags |= E_FIRST;
  960.         for (i=POS_LST_BLK, l = &Buf[i]; *l && i > POS_FST_BLK; i--, l--)
  961.             ;
  962.         count = POS_LST_BLK - i;
  963.         if (*l)
  964.             count++;
  965.         else
  966.             l++;
  967.         if (count != Buf[POS_NUM_BLK])
  968.             *flags |= E_COUNT;
  969.         ((struct Ext *)obj)->num = count;
  970.         if (count)
  971.         {
  972. DEBUGMEM_NAME("An Ext Blk List");
  973.             LAlloc(l2, count, StrExt);
  974.             Copy(l2, l, count, sizeof(ulong));
  975.             ((struct Ext *)obj)->blocks = l2;
  976.         }
  977.         else
  978.             ((struct Ext *)obj)->blocks = (ulong *)NULL;
  979.         ((struct Ext *)obj)->parent = Buf[POS_PAR];
  980.         ((struct Ext *)obj)->extension = Buf[POS_EXT];
  981.         break;
  982.     case TYP_DAT:
  983.         Rem->type = I_DAT;
  984.         if (Seek)
  985.             (struct Dat *)obj = Rem->Obj.dat;
  986.         else
  987.         {
  988. DEBUGMEM_NAME("A Dat");
  989.             ZAlloc((struct Dat *)obj);
  990.             Rem->Obj.dat = (struct Dat *)obj;
  991.         }
  992.         ((struct Dat *)obj)->key = Buf[POS_KEY];
  993.         ((struct Dat *)obj)->seqnum = Buf[POS_D_SEQ_NUM];
  994.         ((struct Dat *)obj)->size = Buf[POS_D_DAT_SIZ];
  995.         ((struct Dat *)obj)->nextd = Buf[POS_D_NXT_DAT];
  996.         if (((struct Dat *)obj)->nextd)
  997.             if (((struct Dat *)obj)->size != (BLOCK_SIZE - (POS_FST_BLK << 2L)))
  998.                 *flags |= E_SHORT;
  999.         break;
  1000.     default:
  1001.         Rem->type = I_UNK;
  1002.         break;
  1003.     }
  1004.     if (Rem->type != I_UNK && (Rem->type != I_DAT || FileSystem == IS_OFS))
  1005.         if (DosChecksum(Buf))
  1006.             *flags |= E_CHKSUM;
  1007. DBGS("<gb");
  1008. }
  1009.  
  1010. Static rchk(Rem, num, blk, typ, want)
  1011. REG    struct    Info    *Rem;
  1012. REG    ulong    num;
  1013. REG    ulong    blk;
  1014. REG    char    *typ;
  1015. REG    char    *want;
  1016. {
  1017.     if (blk < Stuff.Info.res || blk > (Stuff.Info.End - Stuff.Info.Begin))
  1018.     {    bad(Rem, num, B_RANGE, typ, want, blk);
  1019.         return(0);
  1020.     }
  1021.     return(!0);
  1022. }
  1023.  
  1024. Static int unreadable(Rem, num, Str, par)
  1025. REG    struct    Info    *Rem;
  1026. REG    ulong    num;
  1027. REG    char    *Str;
  1028. REG    ulong    par;
  1029. {
  1030.     if (Rem->type == I_UNREADABLE)
  1031.     {    bad(Rem, num, B_UNR, Str, Rem->Obj.ret, par);
  1032.         return(!0);
  1033.     }
  1034.     else
  1035.         return(0);
  1036. }
  1037.  
  1038. Static FreeSeek(Rem)
  1039. REG    struct    Info    *Rem;
  1040. {
  1041.     REG    ulong    *l;
  1042.     REG    ulong    count;
  1043.  
  1044. DBGS(">FS");
  1045.  
  1046.     if (Seek)
  1047.         switch(Rem->type)
  1048.         {
  1049.         case I_ROOT:
  1050.             l = Rem->Obj.root->bblocks;
  1051.             if (l)
  1052.             {    for (count = 1; *l; l++, count++)
  1053.                     ;
  1054.                 FreeMem(Rem->Obj.root->bblocks, ULONGS(count));
  1055.             }
  1056.             l = Rem->Obj.root->blocks;
  1057.             if (l)
  1058.             {    for (count = 1; *l; l++, count++)
  1059.                     ;
  1060.                 FreeMem(Rem->Obj.root->blocks, ULONGS(count));
  1061.             }
  1062.             break;
  1063.         case I_DIR:
  1064.             l = Rem->Obj.dir->blocks;
  1065.             if (l)
  1066.             {    for (count = 1; *l; l++, count++)
  1067.                     ;
  1068.                 FreeMem(Rem->Obj.dir->blocks, ULONGS(count));
  1069.             }
  1070.             break;
  1071.         case I_FIL:
  1072.             if (Rem->Obj.fil->blocks)
  1073.                 FreeMem(Rem->Obj.fil->blocks, ULONGS(Rem->Obj.fil->num));
  1074.             break;
  1075.         case I_EXT:
  1076.             if (Rem->Obj.ext->blocks)
  1077.                 FreeMem(Rem->Obj.ext->blocks, ULONGS(Rem->Obj.ext->num));
  1078.             break;
  1079. /*
  1080.         case I_DAT:
  1081.         case I_S_LNK:
  1082.         case I_H_LNK_DIR:
  1083.         case I_H_LNK_FIL:
  1084. */
  1085.         default:
  1086.             break;
  1087.         }
  1088. DBGS("<FS");
  1089. }
  1090.  
  1091. Static CheckUsed(num, Rem, str, par)
  1092. REG    ulong    num;
  1093. REG    struct    Info    *Rem;
  1094. REG    char    *str;
  1095. REG    ulong    par;
  1096. {
  1097.     if (FileSystem == IS_FFS)
  1098.         if (Seek)
  1099.         {    if (BMAP_TST(num))
  1100.                 bad(Rem, num, B_USED, str, par);
  1101.             else
  1102.                 BMAP_SET(num);
  1103.         }
  1104.         else
  1105.         {    if (Rem->flags & I_USED)
  1106.                 switch(Rem->type)
  1107.                 {
  1108.                 case I_DAT:    /* well maybe? ;-) */
  1109.                     bad(Rem, num, B_USEDBY, str, par, Rem->Obj.dat->key);
  1110.                     break;
  1111.                 case I_DIR:
  1112.                 case I_FIL:
  1113.                 case I_EXT:
  1114.                 case I_S_LNK:
  1115.                 case I_H_LNK_DIR:
  1116.                 case I_H_LNK_FIL:
  1117.                     bad(Rem, num, B_USEDBY, str, par, Rem->Obj.dir->parent);
  1118.                     break;
  1119. /* Usually FFS Data Block
  1120.                 case I_ROOT:
  1121.                 case I_UNK:
  1122.                 case I_UNREADABLE:
  1123. */
  1124.                 default:
  1125.                     bad(Rem, num, B_USED, str, par);
  1126.                     break;
  1127.                 }
  1128.             else
  1129.                 Rem->flags |= I_USED;
  1130.         }
  1131. }
  1132.  
  1133. Static long ChkDat(num, hed, Rem, key)
  1134. REG    ulong    num;
  1135. REG    ulong    hed;
  1136. REG    struct    Info    *Rem;
  1137. REG    ulong    key;
  1138. {
  1139.     REG    ulong  *l;
  1140.  
  1141.     DoCache = !0;
  1142.  
  1143.     if (Seek)
  1144.         Get(Rem, num);
  1145.     else
  1146.         Rem = &InfoList[num];
  1147.  
  1148.     CheckUsed(num, Rem, StrDat, key);
  1149.  
  1150.     if (unreadable(Rem, num, StrDat, hed))
  1151.         return(0);
  1152.  
  1153.     if (FileSystem == IS_FFS)
  1154.     {    FreeSeek(Rem);
  1155.         return(1);
  1156.     }
  1157.  
  1158.     PrevD = num;
  1159.     NextD = ULONGMAX;
  1160.     SeqNum++;
  1161.  
  1162.     if (Rem->type != I_DAT)
  1163.     {    bad(Rem, num, B_TYP, StrDat, hed);
  1164.  
  1165.         if (Rem->flags & E_CHKSUM)
  1166.             bad(Rem, num, B_CHKSUM, StrDat, hed);
  1167.  
  1168.         FreeSeek(Rem);
  1169.         return(0);
  1170.     }
  1171.     else
  1172.     {    if (Rem->Obj.dat->key != hed)
  1173.             bad(Rem, num, B_HED, StrDat, Rem->Obj.dat->key, hed);
  1174.         if (Rem->flags & E_CHKSUM)
  1175.             bad(Rem, num, B_CHKSUM, StrDat, hed);
  1176.  
  1177.         if (Rem->Obj.dat->seqnum != SeqNum)
  1178.             bad(Rem, num, B_SEQ, StrDat, SeqNum, Rem->Obj.dat->seqnum);
  1179.  
  1180.         if (Rem->flags & E_SHORT)
  1181.             bad(Rem, num, B_SHORT, StrDat);
  1182.  
  1183.         NextD = Rem->Obj.dat->nextd;
  1184.         if (NextD)
  1185.             rchk(Rem, num, NextD, StrDat, StrNextD);
  1186.  
  1187.         FreeSeek(Rem);
  1188.         return(Rem->Obj.dat->size);
  1189.     }
  1190. }
  1191.  
  1192. Static long ChkExt(num, par, Rem)
  1193. ulong    num;
  1194. ulong    par;
  1195. REG    struct    Info    *Rem;
  1196. {
  1197.     REG    ulong  *l;
  1198.     REG    ulong  *l2;
  1199.     REG    ulong  bytesize = 0;
  1200.     REG    int    oBaD = BaD;
  1201.  
  1202.     DoCache = 0;
  1203.  
  1204.     if (Seek)
  1205.         Get(Rem, num);
  1206.     else
  1207.         Rem = &InfoList[num];
  1208.  
  1209.     CheckUsed(num, Rem, StrExt, par);
  1210.  
  1211.     if (unreadable(Rem, num, StrExt, par))
  1212.         return(0);
  1213.  
  1214.     if (Rem->type != I_EXT)
  1215.         bad(Rem, num, B_TYP, StrExt, par);
  1216.     else
  1217.         if (Rem->Obj.ext->parent != par)
  1218.             bad(Rem, num, B_PAR, StrExt, Rem->Obj.ext->parent, par);
  1219.  
  1220.     if (Rem->flags & E_KEY)
  1221.         bad(Rem, num, B_KEY, StrExt, par);
  1222.     if (Rem->flags & E_CHKSUM)
  1223.         bad(Rem, num, B_CHKSUM, StrExt, par);
  1224.  
  1225.     if (Rem->flags & E_COUNT)
  1226.         bad(Rem, num, B_COUNT, StrExt, par);
  1227.     if (Rem->flags & E_FIRST)
  1228.         bad(Rem, num, B_FIRST, StrExt, 0L);
  1229.  
  1230.     if (IgnoreErr || BaD == oBaD)
  1231.     {    l = Rem->Obj.ext->blocks;
  1232.         if (l)
  1233.         {    for (l2 = &l[Rem->Obj.ext->num - 1]; l2 >= l; l2--)
  1234.                 if (rchk(Rem, num, *l2, StrExt, StrDat))
  1235.                 {    if (FileSystem == IS_OFS && NextD != *l2 && NextD != ULONGMAX)
  1236.                         bad(Rem, num, B_NEXTD, StrExt, *l2, PrevD, NextD);
  1237.                     bytesize += ChkDat(*l2, par, Rem+1, num);
  1238.                 }
  1239.             FreeSeek(Rem);
  1240.             if (Rem->Obj.ext->extension && rchk(Rem, num, Rem->Obj.ext->extension, StrExt, StrExt))
  1241.                 bytesize += ChkExt(Rem->Obj.ext->extension, par, Rem);
  1242.                 /* Same Level (and don't need Rem anymore) */
  1243.         }
  1244.         else
  1245.             FreeSeek(Rem);
  1246.     }
  1247.     else
  1248.         FreeSeek(Rem);
  1249.  
  1250.     return(bytesize);
  1251. }
  1252.  
  1253. Static ChkFil(num, par, Rem)
  1254. ulong    num;
  1255. ulong    par;
  1256. REG    struct    Info    *Rem;
  1257. {
  1258.     REG    ulong  *l;
  1259.     REG    ulong  *l2;
  1260.     REG    ulong  bytesize = 0;
  1261.     REG    int    oBaD = BaD;
  1262.     int    flag = 0;
  1263.     struct    Info    *oLastInfo = LastInfo;
  1264.     ulong    oLastBlk = LastBlk;
  1265.  
  1266.     LastInfo = Rem;
  1267.     LastBlk = num;
  1268.  
  1269.     if (Rem->flags & E_KEY)
  1270.         bad(Rem, num, B_KEY, StrFil, par);
  1271.     if (Rem->flags & E_CHKSUM)
  1272.         bad(Rem, num, B_CHKSUM, StrFil, par);
  1273.     if (Rem->flags & E_COUNT)
  1274.         bad(Rem, num, B_COUNT, StrFil, par);
  1275.     if (Rem->flags & E_FIRST)
  1276.     {    if (Rem->Obj.fil->blocks)
  1277.             bad(Rem, num, B_FIRST, StrFil, Rem->Obj.fil->blocks[Rem->Obj.fil->num - 1]);
  1278.         else
  1279.             bad(Rem, num, B_FIRST, StrFil, 0L);
  1280.     }
  1281.     if (Rem->flags & E_BADNAME)
  1282.         bad(Rem, num, B_BADNAME, StrFil);
  1283.     if (Rem->flags & E_PREVLINK)
  1284.         bad(Rem, num, B_PREVLINK, StrFil);
  1285.     if (Rem->flags & E_OFSLINK)
  1286.         bad(Rem, num, B_OFSLINK, StrFil);
  1287.  
  1288.     if (Rem->Obj.fil->parent != par)
  1289.         bad(Rem, num, B_PAR, StrFil, Rem->Obj.fil->parent, par);
  1290.  
  1291.     if (Rem->Obj.fil->next)
  1292.     {    rchk(Rem, num, Rem->Obj.fil->next, StrFil, StrNext);
  1293.         MoveMaybe(num);
  1294.     }
  1295.  
  1296.     if (IgnoreErr || BaD == oBaD)
  1297.     {    SeqNum = 0L;
  1298.         l = Rem->Obj.fil->blocks;
  1299.         if (l)
  1300.         {    for(l2 = &l[Rem->Obj.fil->num - 1]; l2 >= l; l2--)
  1301.                 if (rchk(Rem, num, *l2, StrFil, StrDat))
  1302.                 {    if (flag)
  1303.                     {    if (FileSystem == IS_OFS && NextD != *l2 && NextD != ULONGMAX)
  1304.                             bad(Rem, num, B_NEXTD, StrFil, *l2, PrevD, NextD);
  1305.                     }
  1306.                     else
  1307.                         flag = !0;
  1308.                     bytesize += ChkDat(*l2, num, Rem+1, num);
  1309.                 }
  1310.             if (Rem->Obj.fil->extension && rchk(Rem, num, Rem->Obj.fil->extension, StrFil, StrExt))
  1311.                 bytesize += ChkExt(Rem->Obj.fil->extension, num, Rem+1);
  1312.             if (FileSystem == IS_OFS && NextD && NextD != ULONGMAX)
  1313.                 bad(Rem, num, B_NEXTD, StrFil, 0L, PrevD, NextD);
  1314.  
  1315.             if (FileSystem == IS_OFS)
  1316.                 if (bytesize != Rem->Obj.fil->bytesize)
  1317.                     bad(Rem, num, B_BYTESIZE, StrFil, bytesize, Rem->Obj.fil->bytesize);
  1318.  
  1319.             if (FileSystem == IS_FFS)
  1320.             {    Rem->Obj.fil->bytesize += 511;
  1321.                 Rem->Obj.fil->bytesize /= 512;    /* Calculate number of blocks - any other check available ???? */
  1322.                 if (bytesize != Rem->Obj.fil->bytesize)
  1323.                     bad(Rem, num, B_BLOCKSIZE, StrFil, bytesize, Rem->Obj.fil->bytesize);
  1324.             }
  1325.         }
  1326.         LastInfo = oLastInfo;
  1327.         LastBlk = oLastBlk;
  1328.  
  1329.         FreeSeek(Rem);
  1330.  
  1331.         if (Rem->Obj.fil->chain && rchk(Rem, num, Rem->Obj.fil->chain, StrFil, StrChain))
  1332.             ChkEtc(Rem->Obj.fil->chain, par, Rem);
  1333.             /* Same Level (and don't need Rem anymore) */
  1334.     }
  1335.     else
  1336.     {    LastInfo = oLastInfo;
  1337.         LastBlk = oLastBlk;
  1338.  
  1339.         FreeSeek(Rem);
  1340.     }
  1341. }
  1342.  
  1343. Static ChkDir(num, par, Rem)
  1344. REG    ulong    num;
  1345. REG    ulong    par;
  1346. REG    struct    Info    *Rem;
  1347. {
  1348.     REG    ulong  *l;
  1349.     REG    int    oBaD = BaD;
  1350.     struct    Info    *oLastInfo = LastInfo;
  1351.     ulong    oLastBlk = LastBlk;
  1352.  
  1353.     LastInfo = Rem;
  1354.     LastBlk = num;
  1355.  
  1356.     if (Rem->flags & E_KEY)
  1357.         bad(Rem, num, B_KEY, StrDir, par);
  1358.     if (Rem->flags & E_CHKSUM)
  1359.         bad(Rem, num, B_CHKSUM, StrDir, par);
  1360.     if (Rem->flags & E_BADNAME)
  1361.         bad(Rem, num, B_BADNAME, StrDir);
  1362.     if (Rem->flags & E_PREVLINK)
  1363.         bad(Rem, num, B_PREVLINK, StrDir);
  1364.     if (Rem->flags & E_OFSLINK)
  1365.         bad(Rem, num, B_OFSLINK, StrDir);
  1366.  
  1367.     if (Rem->Obj.dir->parent != par)
  1368.         bad(Rem, num, B_PAR, StrDir, Rem->Obj.dir->parent, par);
  1369.  
  1370.     if (Rem->Obj.dir->next)
  1371.     {    rchk(Rem, num, Rem->Obj.dir->next, StrDir, StrNext);
  1372.         MoveMaybe(num);
  1373.     }
  1374.  
  1375.     if (IgnoreErr || BaD == oBaD)
  1376.     {    l = Rem->Obj.dir->blocks;
  1377.         if (l)
  1378.             for (; *l; l++)
  1379.                 if (rchk(Rem, num, *l, StrDir, StrEtc))
  1380.                     ChkEtc(*l, num, Rem+1);
  1381.  
  1382.         LastInfo = oLastInfo;
  1383.         LastBlk = oLastBlk;
  1384.  
  1385.         FreeSeek(Rem);
  1386.  
  1387.         if (Rem->Obj.dir->chain && rchk(Rem, num, Rem->Obj.dir->chain, StrDir, StrChain))
  1388.             ChkEtc(Rem->Obj.dir->chain, par, Rem);
  1389.             /* Same Level (and don't need Rem anymore) */
  1390.     }
  1391.     else
  1392.     {    LastInfo = oLastInfo;
  1393.         LastBlk = oLastBlk;
  1394.  
  1395.         FreeSeek(Rem);
  1396.     }
  1397. }
  1398.  
  1399. Static ChkLnk(num, par, Rem)
  1400. REG    ulong    num;
  1401. REG    ulong    par;
  1402. REG    struct    Info    *Rem;
  1403. {
  1404.     REG    ulong  *l;
  1405.     REG    int    oBaD = BaD;
  1406.     struct    Info    *oLastInfo = LastInfo;
  1407.     ulong    oLastBlk = LastBlk;
  1408.  
  1409.     LastInfo = Rem;
  1410.     LastBlk = num;
  1411.  
  1412.     if (Rem->flags & E_KEY)
  1413.         bad(Rem, num, B_KEY, StrSoftLnk, par);
  1414.     if (Rem->flags & E_CHKSUM)
  1415.         bad(Rem, num, B_CHKSUM, StrSoftLnk, par);
  1416.     if (Rem->flags & E_BADNAME)
  1417.         bad(Rem, num, B_BADNAME, StrSoftLnk);
  1418.     if (Rem->flags & E_PREVLINK)
  1419.         bad(Rem, num, B_PREVLINK, StrRoot);
  1420.     if (Rem->flags & E_NEXTLINK)
  1421.         bad(Rem, num, B_NEXTLINK, StrRoot);
  1422.     if (Rem->flags & E_OFSLINK)
  1423.         bad(Rem, num, B_OFSLINK, StrSoftLnk);
  1424.  
  1425.     if (Rem->Obj.lnk->parent != par)
  1426.         bad(Rem, num, B_PAR, StrSoftLnk, Rem->Obj.lnk->parent, par);
  1427.  
  1428.     LastInfo = oLastInfo;
  1429.     LastBlk = oLastBlk;
  1430.  
  1431.     FreeSeek(Rem);
  1432.  
  1433.     if (IgnoreErr || BaD == oBaD)
  1434.     {    if (Rem->Obj.lnk->chain && rchk(Rem, num, Rem->Obj.lnk->chain, StrSoftLnk, StrChain))
  1435.             ChkEtc(Rem->Obj.lnk->chain, par, Rem);
  1436.             /* Same Level (and don't need Rem anymore) */
  1437.     }
  1438. }
  1439.  
  1440. Static ChkDirLnk(num, par, Rem)
  1441. REG    ulong    num;
  1442. REG    ulong    par;
  1443. REG    struct    Info    *Rem;
  1444. {
  1445.     REG    ulong  *l;
  1446.     REG    int    oBaD = BaD;
  1447.     struct    Info    *oLastInfo = LastInfo;
  1448.     ulong    oLastBlk = LastBlk;
  1449.  
  1450.     LastInfo = Rem;
  1451.     LastBlk = num;
  1452.  
  1453.     if (Rem->flags & E_KEY)
  1454.         bad(Rem, num, B_KEY, StrDirLnk, par);
  1455.     if (Rem->flags & E_CHKSUM)
  1456.         bad(Rem, num, B_CHKSUM, StrDirLnk, par);
  1457.     if (Rem->flags & E_BADNAME)
  1458.         bad(Rem, num, B_BADNAME, StrDirLnk);
  1459.     if (Rem->flags & E_PREVLINK)
  1460.         bad(Rem, num, B_NOPREVLINK, StrDirLnk);
  1461.     if (Rem->flags & E_OFSLINK)
  1462.         bad(Rem, num, B_OFSLINK, StrDirLnk);
  1463.  
  1464.     if (Rem->Obj.dirlnk->parent != par)
  1465.         bad(Rem, num, B_PAR, StrDirLnk, Rem->Obj.dirlnk->parent, par);
  1466.  
  1467.     if (Rem->Obj.dirlnk->prev)
  1468.         rchk(Rem, num, Rem->Obj.dirlnk->prev, StrDirLnk, StrPrev);
  1469.     if (Rem->Obj.dirlnk->next)
  1470.         rchk(Rem, num, Rem->Obj.dirlnk->next, StrDirLnk, StrNext);
  1471.  
  1472.     MoveMaybe(num);
  1473.  
  1474.     LastInfo = oLastInfo;
  1475.     LastBlk = oLastBlk;
  1476.  
  1477.     FreeSeek(Rem);
  1478.  
  1479.     if (IgnoreErr || BaD == oBaD)
  1480.     {    if (Rem->Obj.dirlnk->chain && rchk(Rem, num, Rem->Obj.dirlnk->chain, StrDirLnk, StrChain))
  1481.             ChkEtc(Rem->Obj.dirlnk->chain, par, Rem);
  1482.             /* Same Level (and don't need Rem anymore) */
  1483.     }
  1484. }
  1485.  
  1486. Static ChkFilLnk(num, par, Rem)
  1487. REG    ulong    num;
  1488. REG    ulong    par;
  1489. REG    struct    Info    *Rem;
  1490. {
  1491.     REG    ulong  *l;
  1492.     REG    int    oBaD = BaD;
  1493.     struct    Info    *oLastInfo = LastInfo;
  1494.     ulong    oLastBlk = LastBlk;
  1495.  
  1496.     LastInfo = Rem;
  1497.     LastBlk = num;
  1498.  
  1499.     if (Rem->flags & E_KEY)
  1500.         bad(Rem, num, B_KEY, StrFilLnk, par);
  1501.     if (Rem->flags & E_CHKSUM)
  1502.         bad(Rem, num, B_CHKSUM, StrFilLnk, par);
  1503.     if (Rem->flags & E_BADNAME)
  1504.         bad(Rem, num, B_BADNAME, StrFilLnk);
  1505.     if (Rem->flags & E_PREVLINK)
  1506.         bad(Rem, num, B_NOPREVLINK, StrFilLnk);
  1507.     if (Rem->flags & E_OFSLINK)
  1508.         bad(Rem, num, B_OFSLINK, StrFilLnk);
  1509.  
  1510.     if (Rem->Obj.fillnk->parent != par)
  1511.         bad(Rem, num, B_PAR, StrFilLnk, Rem->Obj.fillnk->parent, par);
  1512.  
  1513.     if (Rem->Obj.fillnk->prev)
  1514.         rchk(Rem, num, Rem->Obj.fillnk->prev, StrFilLnk, StrPrev);
  1515.     if (Rem->Obj.fillnk->next)
  1516.         rchk(Rem, num, Rem->Obj.fillnk->next, StrFilLnk, StrNext);
  1517.  
  1518.     MoveMaybe(num);
  1519.  
  1520.     LastInfo = oLastInfo;
  1521.     LastBlk = oLastBlk;
  1522.  
  1523.     FreeSeek(Rem);
  1524.  
  1525.     if (IgnoreErr || BaD == oBaD)
  1526.     {    if (Rem->Obj.fillnk->chain && rchk(Rem, num, Rem->Obj.fillnk->chain, StrFilLnk, StrChain))
  1527.             ChkEtc(Rem->Obj.fillnk->chain, par, Rem);
  1528.             /* Same Level (and don't need Rem anymore) */
  1529.     }
  1530. }
  1531.  
  1532. Static ChkEtc(num, par, Rem)
  1533. REG    ulong    num;
  1534. REG    ulong    par;
  1535. REG    struct    Info    *Rem;
  1536. {
  1537.     REG    ulong  *l;
  1538.  
  1539.     DoCache = 0;
  1540.  
  1541.     if (Seek)
  1542.         Get(Rem, num);
  1543.     else
  1544.         Rem = &InfoList[num];
  1545.  
  1546.     CheckUsed(num, Rem, StrEtc, par);
  1547.  
  1548.     if (unreadable(Rem, num, StrEtc, par))
  1549.         return;
  1550.  
  1551.     switch(Rem->type)
  1552.     {
  1553.     case I_DIR:
  1554.         ChkDir(num, par, Rem);
  1555.         break;
  1556.     case I_FIL:
  1557.         ChkFil(num, par, Rem);
  1558.         break;
  1559.     case I_S_LNK:
  1560.         ChkLnk(num, par, Rem);
  1561.         break;
  1562.     case I_H_LNK_DIR:
  1563.         ChkDirLnk(num, par, Rem);
  1564.         break;
  1565.     case I_H_LNK_FIL:
  1566.         ChkFilLnk(num, par, Rem);
  1567.         break;
  1568.     default:
  1569.         bad(Rem, num, B_TYP, StrEtc, par);
  1570.         FreeSeek(Rem);
  1571.         break;
  1572.     }
  1573. }
  1574.  
  1575. Static ChkBMap(num, par, Rem)
  1576. REG    ulong    num;
  1577. REG    ulong    par;
  1578. REG    struct    Info    *Rem;
  1579. {
  1580.     DoCache = !0;
  1581.  
  1582.     if (Seek)
  1583.         Get(Rem, num);
  1584.     else
  1585.         Rem = &InfoList[num];
  1586.  
  1587.     CheckUsed(num, Rem, StrBitMap, par);
  1588.  
  1589.     if (unreadable(Rem, num, StrBitMap, par))
  1590.         return;
  1591.  
  1592.     if (Rem->flags & E_CHKSUM)
  1593.         bad(Rem, num, B_CHKSUM, StrBitMap, par);
  1594.  
  1595.     if (Rem->type != I_UNK)
  1596.         bad(Rem, num, B_BITMAP, StrBitMap);
  1597. /* How do I test that this really is a bitmap block? Probably generate a warning */
  1598.  
  1599.     FreeSeek(Rem);
  1600. }
  1601.  
  1602. Static ChkRoot(num, Rem)
  1603. REG    ulong    num;
  1604. REG    struct    Info    *Rem;
  1605. {
  1606.     REG    ulong  *l;
  1607.     REG    int    oBaD = BaD;
  1608.  
  1609. DBGS(">ChkRoot");
  1610.  
  1611.     if (Seek)
  1612.         Get(Rem, num);
  1613.     else
  1614.         Rem = &InfoList[num];
  1615.  
  1616.     LastInfo = Rem;
  1617.     LastBlk = num;
  1618.  
  1619.     CheckUsed(num, Rem, StrRoot, 0L);
  1620.  
  1621.     if (unreadable(Rem, num, StrRoot, 0L))
  1622.         return;
  1623.  
  1624.     if (Rem->type != I_ROOT)
  1625.         bad(Rem, num, B_TYP, StrRoot, 0L);
  1626.     if (Rem->flags & E_BMFLG)
  1627.         bad(Rem, num, B_BMFLG, StrRoot);
  1628.     if (Rem->flags & E_HTSIZ)
  1629.         bad(Rem, num, B_HTSIZ, StrRoot);
  1630.     if (Rem->flags & E_KEY)
  1631.         bad(Rem, num, B_KEY, StrRoot, 0L);
  1632.     if (Rem->flags & E_CHKSUM)
  1633.         bad(Rem, num, B_CHKSUM, StrRoot, 0L);
  1634.     if (Rem->flags & E_BADNAME)
  1635.         bad(Rem, num, B_BADNAME, StrRoot);
  1636.  
  1637. /* appears to be a date in NEXTLINK position
  1638.     if (Rem->flags & E_PREVLINK)
  1639.         bad(Rem, num, B_PREVLINK, StrRoot);
  1640.     if (Rem->flags & E_NEXTLINK)
  1641.         bad(Rem, num, B_NEXTLINK, StrRoot);
  1642. */
  1643.  
  1644.     if (IgnoreErr || BaD == oBaD)
  1645.     {    l = Rem->Obj.root->bblocks;
  1646.         if (!l)
  1647.             bad(Rem, num, B_BMAP, NULL);
  1648.         else
  1649.             for (; *l; l++)
  1650.                 if (rchk(Rem, num, *l, StrRoot, StrBitMap))
  1651.                     ChkBMap(*l, num, Rem+1);
  1652.  
  1653.         l = Rem->Obj.root->blocks;
  1654.         if (l)
  1655.             for (; *l; l++)
  1656.                 if (rchk(Rem, num, *l, StrRoot, StrEtc))
  1657.                     ChkEtc(*l, num, Rem+1);
  1658.     }
  1659.     FreeSeek(Rem);
  1660.  
  1661. DBGS("<ChkRoot");
  1662. }
  1663.  
  1664. Static    ValidateIt()
  1665. {
  1666.     REG    ulong    l;
  1667.     REG    ulong    size;
  1668.     REG    ulong    *bptr;
  1669.  
  1670.     if (Seek)
  1671.         size = MaxDepth;
  1672.     else
  1673.         size = 1L + Stuff.Info.End - Stuff.Info.Begin;
  1674.  
  1675. DEBUGMEM_NAME("InfoList");
  1676.     MPAlloc(InfoList, (sizeof(*InfoList) * size), &GenPoolKey);
  1677.  
  1678.     if (!Seek)
  1679.     {    AkMotorOn(&Stuff);
  1680.         DoCache = !0;
  1681.         for (l = Stuff.Info.Begin; l <= Stuff.Info.End; l++)
  1682.             getblok(l, NULL);
  1683.         AkMotorOff(&Stuff);
  1684.         ChkRoot(Stuff.Info.Root, NULL);
  1685.     }
  1686.     else
  1687.     {    while (size-- > 0)
  1688.         {
  1689. DEBUGMEM_NAME("An InfoList fil");
  1690.             MPAlloc(InfoList[size].Obj.fil, sizeof(struct Fil), &GenPoolKey);
  1691.         }
  1692.         if (FileSystem == IS_FFS)
  1693.         {    size = 1L + Stuff.Info.End - Stuff.Info.Begin;
  1694. DEBUGMEM_NAME("BitMap");
  1695.             MPAlloc(MyBitMap, (size+7)/8, &ZerPoolKey);
  1696.         }
  1697.         AkMotorOn(&Stuff);
  1698.         DoCache = !0;
  1699.         ChkRoot(Stuff.Info.Root, InfoList);
  1700.         AkMotorOff(&Stuff);
  1701.     }
  1702.  
  1703.     CheckLinks();
  1704.  
  1705.     if (BaD || WaR)
  1706.         printf("\nTotal Displayed errors for %s %d, Warnings: %d\n", Device, BaD, WaR);
  1707.     else
  1708.         printf("\nNo errors detected on %s\n", Device);
  1709.  
  1710.     if (DebugLink)
  1711.     {    puts("Links:");
  1712.         if (!LinkHead)
  1713.             puts("\tNone!");
  1714.         else
  1715.         {    while (LinkHead)
  1716.             {    printf("\t%-10s Blk:%10lu Prev:%10lu Next:%10lu\n",
  1717.                     StrType(LinkHead->type),
  1718.                     LinkHead->block,
  1719.                     LinkHead->prev,
  1720.                     LinkHead->next);
  1721.                 LinkHead = LinkHead->another;
  1722.             }
  1723.         }
  1724.         puts("Maybes: (but not!)");
  1725.         if (!LinkMaybe)
  1726.             puts("\tNone!");
  1727.         else
  1728.         {    while (LinkMaybe)
  1729.             {    printf("\t%-10s Blk:%10lu Prev:%10lu Next:%10lu\n",
  1730.                     StrType(LinkMaybe->type),
  1731.                     LinkMaybe->block,
  1732.                     LinkMaybe->prev,
  1733.                     LinkMaybe->next);
  1734.                 LinkMaybe = LinkMaybe->another;
  1735.             }
  1736.         }
  1737.     }
  1738. }
  1739.  
  1740. Static    Val()
  1741. {
  1742.     LONG    ret;
  1743.     ulong    *buf;
  1744.  
  1745.     if (Dev = AkDevOpen(Device, &Stuff))
  1746.         MyError(Dev, Device);
  1747.  
  1748.     if (Inhibit)
  1749.         Inhibited = AkDevInhibit(&Stuff, -1L);
  1750.  
  1751. DEBUGMEM_NAME("Buffer");
  1752.  
  1753.     MPAlloc(Buffer, (long)(BLOCK_SIZE*Cache), &BufPoolKey);
  1754.  
  1755.     AkDevMsg(&(Stuff.Info));
  1756.  
  1757.     if (Ffs || Ofs)         /* Force FS choice */
  1758.     {    if (Ofs)
  1759.             FileSystem = IS_OFS;
  1760.         else
  1761.             FileSystem = IS_FFS;
  1762.     }
  1763.     else
  1764.     {    if (ShowFileSystem)
  1765.             printf("FileSystemHandler is \"%s\"\n", Stuff.Info.fsys);
  1766.  
  1767.         printf("Boot Block File System ... ");
  1768.         fflush(stdout);
  1769.  
  1770.         FileSystem = IS_FFS;    /* Assume - change if wrong */
  1771.  
  1772.         AkMotorOn(&Stuff);
  1773.         DoCache = !Seek;
  1774.         ret = CacheRead(Stuff.Info.Begin, &buf);
  1775.         AkMotorOff(&Stuff);
  1776.  
  1777.         if (ret)
  1778.             printf("Error 0x%lx on Read Block Zero - Assumed FFS\n", ret);
  1779.         else
  1780.         {    if ((*buf & 0xffffff00) != 0x444f5300)
  1781.                 printf("Doesn't appear to be DOS - Assumed FFS\n");
  1782.             else
  1783.             {    if ((*buf & 0xff) == 0)
  1784.                 {    FileSystem = IS_OFS;
  1785.                     printf("Appears to be OFS\n");
  1786.                 }
  1787.                 else
  1788.                     printf("Appears to be FFS or similar\n");
  1789.             }
  1790.         }
  1791.     }
  1792.     ValidateIt();
  1793. }
  1794.  
  1795. main(argc, argv)
  1796. int    argc;
  1797. char    *argv[];
  1798. {
  1799.     REG    int    idx;
  1800.  
  1801.     cli = argc;
  1802.  
  1803.     DO_QUAL();
  1804.  
  1805.     if (Cache > 1)
  1806.         Cache += 2;
  1807.  
  1808.     if (!Quiet && cli)
  1809.         STARTUP_MSG;
  1810.  
  1811.     OPEN_LIB(IBASE, "intuition.library", INTUITION_REV);
  1812.  
  1813.     PoolInit(&BufPoolKey, 0L, MEMF_CHIP);
  1814.     PoolInit(&GenPoolKey, PoolSize, 0L);
  1815.     PoolInit(&ZerPoolKey, 0L, MEMF_CLEAR);
  1816.  
  1817.     Val();
  1818.  
  1819.     if (StatCache)
  1820.     {    ulong    BTot = ReadSmall*2 + ReadLNum;
  1821.         ulong    RTot = HitSmall + HitLarge + ReadSmall + ReadLarge;
  1822.  
  1823. #define PER(x)  (RTot ? (double)(x) / (double)(RTot) * (double)(100): (double)0)
  1824.  
  1825.         printf("Cache Statistics (Real Time) - Cache = 2:%d\n", Cache-2);
  1826.         if (Cache == 1)
  1827.             puts("Well ... first you need to HAVE a cache! (Try /cache=75)");
  1828.         else
  1829.         {    printf("Blocks Requested....... %10lu\n", RTot);
  1830.             printf("Blocks Read............ %10lu\n", BTot);
  1831.             printf("Average Reads/Request.. %10.2lf\n", (double)(BTot) / (double)(RTot));
  1832.             printf("Total µsecs Cache Code. %10lu\n", MicCode);
  1833.             if (MicCode)
  1834.                 printf("Average µsec/CodeReq... %10.2lf\n",
  1835.                     (double)(MicCode) / (double)(HitSmall + HitLarge));
  1836.             printf("Total µsecs Cache IOReq %10lu\n", MicRead);
  1837.             if (MicRead)
  1838.                 printf("Average µsec/IOReq..... %10.2lf\n",
  1839.                     (double)(MicRead) / (double)(ReadSmall + ReadLarge));
  1840.             printf("Total µsecs Cache Req.. %10lu\n", MicCode + MicRead);
  1841.             if (MicCode || MicRead)
  1842.                 printf("Average µsec/Request... %10.2lf\n",
  1843.                     ((double)(MicCode) + (double)(MicRead)) / (double)(RTot));
  1844.             printf("Hits on Small Cache.... %10lu %6.2lf%%\n", HitSmall, PER(HitSmall));
  1845.             printf("Hits on Large Cache.... %10lu %6.2lf%%\n", HitLarge, PER(HitLarge));
  1846.             printf("Reads to Small Cache... %10lu %6.2lf%%\n", ReadSmall, PER(ReadSmall));
  1847.             printf("Reads to Large Cache... %10lu %6.2lf%%\n", ReadLarge, PER(ReadLarge));
  1848.         }
  1849.     }
  1850.  
  1851.     Cleanup();
  1852. }
  1853.  
  1854. MyError(num, why)
  1855. REG    long    num;
  1856. REG    char    *why;
  1857. {
  1858.     ERROR_INIT
  1859.  
  1860.     if (Inhibited)
  1861.         AkDevInhibit(&Stuff, 0L);
  1862.  
  1863.     if (!Dev)
  1864.         AkDevClose(&Stuff);
  1865.  
  1866.     ERROR_TEST
  1867.         CASE_ERR_TOODEEP
  1868.         CASE_ERR_AKDEVALL
  1869.         CASE_ERR_NOVAL
  1870.         CASE_ERR_NOMEM
  1871.         CASE_ERR_NOLIB
  1872.         CASE_ERR_BADFIL
  1873.     ERROR_END(FACILITY_VAL)
  1874.  
  1875.     PoolFree(&ZerPoolKey);
  1876.     PoolFree(&GenPoolKey);
  1877.     PoolFree(&BufPoolKey);
  1878.  
  1879.     if (IBASE)
  1880.         CloseLibrary(IBASE);
  1881.  
  1882.     CLEANUP_QUAL();
  1883.  
  1884.     ERROR_EXIT
  1885. }
  1886.